using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Direct3D = Microsoft.DirectX.Direct3D;

using DirectShowLib;

namespace DirectShowLib.Sample
{
    public class Compositor : IVMRImageCompositor9, IDisposable
    {
        private IntPtr unmanagedDevice;
        private Device device;
        private Direct3D.Font d3dFont;
        private System.Drawing.Font gdiFont;
        
        public Compositor()
        {
            Device.IsUsingEventHandlers = false;
        }

        #region IVMRImageCompositor9 Membres

        public int CompositeImage(IntPtr pD3DDevice, IntPtr pddsRenderTarget, AMMediaType pmtRenderTarget, long rtStart, long rtEnd, int dwClrBkGnd, VMR9VideoStreamInfo[] pVideoStreamInfo, int cStreams)
        {
            try
            {
               
                // Just in case the filter call CompositeImage before InitCompositionDevice (this sometime occure)
                if (unmanagedDevice != pD3DDevice)
                {
                    SetManagedDevice(pD3DDevice);
                }

                Marshal.AddRef(pddsRenderTarget);
                Marshal.AddRef(pVideoStreamInfo[0].pddsVideoSurface);

                using (var renderTarget = new Surface(pddsRenderTarget))
                {
                    var renderTargetDesc = renderTarget.Description;
                    var renderTargetRect = new Rectangle(0, 0, renderTargetDesc.Width, renderTargetDesc.Height);

                    using (var surface = new Surface(pVideoStreamInfo[0].pddsVideoSurface))
                    {
                        var surfaceRect = new Rectangle(0, 0, surface.Description.Width, surface.Description.Height);

                        device.SetRenderTarget(0, renderTarget);
                        device.StretchRectangle(surface, surfaceRect, renderTarget, renderTargetRect, TextureFilter.None);
     
                    }
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());
            }

            return 0;
        }

        public int InitCompositionDevice(IntPtr pD3DDevice)
        {
            try
            {
                // Init the compositor with this unamanaged device
                if (unmanagedDevice != pD3DDevice)
                {
                    SetManagedDevice(pD3DDevice);
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());
            }

            // return a success to the filter
            return 0;
        }

        public int SetStreamMediaType(int dwStrmID, AMMediaType pmt, bool fTexture)
        {
            // This method is called many times with pmt == null
            if (pmt == null)
                return 0;

            // This sample don't use this method... but return a success
            return 0;
        }

        public int TermCompositionDevice(IntPtr pD3DDevice)
        {
            try
            {
                // Free the resources each time this method is called
                unmanagedDevice = IntPtr.Zero;
                FreeResources();
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());
            }

            // return a success to the filter
            return 0;
        }
        
        #endregion

        #region IDisposable Membres

        public void Dispose()
        {
            // free resources
            FreeResources();
        }

        #endregion

        private void FreeResources()
        {
            if (d3dFont != null)
            {
                d3dFont.Dispose();
                d3dFont = null;
            }

       
            if (device != null)
            {
                device.Dispose();
                device = null;
            }

            if (gdiFont != null)
            {
                gdiFont.Dispose();
                gdiFont = null;
            }
        }

        private void SetManagedDevice(IntPtr unmanagedDevice)
        {
            // Start by freeing everything
            FreeResources();

            // Create a managed Device from the unmanaged pointer
            // The constructor don't call IUnknown.AddRef but the "destructor" seem to call IUnknown.Release
            // Direct3D seem to be happier with that according to the DirectX log
            Marshal.AddRef(unmanagedDevice);
            this.unmanagedDevice = unmanagedDevice;
            device = new Device(unmanagedDevice);

            // Load a bitmap (the spider) from embedded resources. This is a png file with alpha transparency
            /*using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("DirectShowLib.Sample.redspider.png"))
            {
              spiderTex = TextureLoader.FromStream(device, stream, D3DX.Default, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None, Format.A8R8G8B8, Pool.Default, Filter.None, Filter.None, 0);
              SurfaceDescription spiderDesc = spiderTex.GetLevelDescription(0);
              spiderSize = new Size(spiderDesc.Width, spiderDesc.Height);
            }*/
        }

    }
}
